#include "messageshowarea.h"
#include "debug.h"
#include "mainwidget.h"

/***********************************
 * 消息展示区
 **********************************/

MessageShowArea::MessageShowArea()
{
    // 1. 初始化基本属性
    this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    this->setWidgetResizable(true);
    // 设置滚动条样式
    QString style = "QScrollBar:vertical {border: none;background: rgb(225,225,225);width: 10px;margin: 0px 0px 0px 0px;}\
        QScrollBar::handle:vertical {background: #c1c1c1;min-height: 20px;border-radius: 5px;}\
        QScrollBar::handle:vertical:hover {background: #a8a8a8;}\
        QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {height: 0px;}\
        QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {background: none;}";
    this->verticalScrollBar()->setStyleSheet(style);
    this->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { height: 0;}");
    this->setStyleSheet("QScrollArea { border: none; }");

    // 2. 创建 Container 这样的 widget, 作为包含内部元素的容器
    container = new QWidget();
    this->setWidget(container);

    // 3. 给 container 添加布局管理器
    QVBoxLayout* vlayout = new QVBoxLayout();
    vlayout->setSpacing(0);
    vlayout->setContentsMargins(0,0,0,0);
    container->setLayout(vlayout);

// 添加 "构造测试数据" 逻辑.
#ifdef TEST_UI
    UserInfo userInfo;
    userInfo.userId = QString::number(100);
    userInfo.nickname = "小短腿";
    userInfo.description = "我是大帅哥";
    userInfo.phone = "15019735211";
    userInfo.avatar = QIcon(":/resource/image/defaultAvatar.png");

    Message msg = Message::createMeaasge(model::TEXT_TYPE,"1",userInfo,QString("这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息这是测试一条测试消息").toUtf8());
    this->addMessage(false,msg);

    for(int i = 0;i < 10;++i)
    {
        userInfo.userId = QString::number(100 + i + 1);
        Message msg = Message::createMeaasge(model::TEXT_TYPE,QString::number(i),userInfo,QString("我要好好敲代码").toUtf8());
        this->addMessage(true,msg);
    }
#endif
}

void MessageShowArea::addMessage(bool isLeft, const Message &msg)
{
    // 构造 MessageItem, 添加到布局管理器中.
    MessageItem* msgItem = MessageItem::makeMessageItem(isLeft,msg);
    container->layout()->addWidget(msgItem);

}

void MessageShowArea::addFrontMessage(bool isLeft, const Message &msg)
{
    MessageItem* msgItem = MessageItem::makeMessageItem(isLeft,msg);
    QVBoxLayout* vlayout = dynamic_cast<QVBoxLayout*>(container->layout());
    vlayout->insertWidget(0,msgItem);
}

void MessageShowArea::clear()
{
    // 遍历布局管理器, 删除里面的元素
    QLayout* layout = container->layout();
    for(int i = layout->count() - 1;i >= 0;--i)
    {
        QLayoutItem* item = layout->takeAt(i);
        if(item != nullptr && item->widget() != nullptr)
        {
            delete item->widget();
        }
    }
}

/***********************************
 * 消息元素
 **********************************/
MessageItem::MessageItem(bool isLeft)
    :_isLeft(isLeft)
{}

MessageItem* MessageItem::makeMessageItem(bool isLeft, const Message &message)
{
    // 1. 创建对象和布局管理器
    MessageItem* msgItem = new MessageItem(isLeft);
    QGridLayout* glayout = new QGridLayout();
    glayout->setSpacing(5);
    glayout->setContentsMargins(10,0,10,0);
    // 这个 MessageItem 最低不能低于 100
    msgItem->setMinimumHeight(100);
    msgItem->setLayout(glayout);

    // 2. 创建头像
    QPushButton* avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(40,40);
    avatarBtn->setIconSize(QSize(40,40));
    avatarBtn->setIcon(QIcon(message.sender.avatar));
    avatarBtn->setStyleSheet("QPushButton { border: none;}");
    if(isLeft)
    {
        glayout->addWidget(avatarBtn,0, 0, 2, 1,Qt::AlignTop | Qt::AlignLeft);
    }
    else
    {
        glayout->addWidget(avatarBtn,0, 1, 2, 1,Qt::AlignTop | Qt::AlignLeft);
    }

    // 3. 创建名字和时间
    QLabel* nameLabel = new QLabel();
    nameLabel->setText(message.sender.nickname + "|" + message.time);
    nameLabel->setAlignment(Qt::AlignBottom);
    nameLabel->setStyleSheet("QLabel { font-size: 12px; color: rgb(178, 178, 178); }");
    if(isLeft)
    {
        glayout->addWidget(nameLabel,0,1);
    }
    else
    {
        glayout->addWidget(nameLabel,0,0,Qt::AlignRight);
    }

    // 4. 创建消息体
    QWidget* contentWidget;
    switch(message.messageType)
    {
    case MessageType::TEXT_TYPE:
        contentWidget = makeTextMessageTiem(isLeft,message.content);
        break;
    case MessageType::IMAGE_TYPE:
        contentWidget = makeImageMessageTiem();
        break;
    case MessageType::FILE_TYPE:
        contentWidget = makeFileMessageTiem();
        break;
    case MessageType::SPEECH_TYPE:
        contentWidget = makeSpeechMessageTiem();
        break;
    default:
        LOG_DEBUG << "错误的消息类型! messageType=" << message.messageType;
        break;
    };

    if(isLeft)
    {
        glayout->addWidget(contentWidget,1,1);
    }
    else
    {
        glayout->addWidget(contentWidget,1,0);
    }

    // 5. 点击头像显示用户信息
    connect(avatarBtn,&QPushButton::clicked,msgItem,[=](){
        MainWidget* mainWidget = MainWidget::getInstance();
        userInfoWidget* userinfoWidget = new userInfoWidget(mainWidget,message.sender);
        userinfoWidget->show();
    });

    return msgItem;
}

QWidget *MessageItem::makeTextMessageTiem(bool isLeft,const QString& message)
{
    MessageContentLabel* msgContentLabel = new MessageContentLabel(isLeft,model::MessageType::TEXT_TYPE,message.toUtf8());
    return msgContentLabel;
}

QWidget *MessageItem::makeImageMessageTiem()
{
    return nullptr;
}

QWidget *MessageItem::makeFileMessageTiem()
{
    return nullptr;
}

QWidget *MessageItem::makeSpeechMessageTiem()
{
    return nullptr;
}

/****************************
 * 创建类表示 "文本消息" 正文部分
 ***************************/
MessageContentLabel::MessageContentLabel(bool isLeft, MessageType msgType, const QByteArray &content)
    :_isLeft(isLeft)
{
    // 设置一下 SizePolicy
    this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    // 设置字体
    QFont font;
    font.setFamily("宋体");
    font.setPixelSize(16);

    this->label = new QLabel(this);
    this->label->setText(content);
    this->label->setFont(font);
    this->label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    this->label->setWordWrap(true);
    this->label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");

}

// 这个函数会该控件被显示的时候自动调用到.
void MessageContentLabel::paintEvent(QPaintEvent *event)
{
    (void)event;
    // 1. 获取到父元素的宽度
    QObject* object = this->parent();
    if(!object->isWidgetType())
    {
        // 当前这个对象的父元素不是预期的 QWidget, 此时不需要进行任何后续的绘制操作.
        return;
    }
    QWidget* parent = dynamic_cast<QWidget*>(object);
    // 拿到的是文本框不超过的显示宽度
    int width = parent->width() * 0.6;

    // 2. 计算当前文本, 如果是一行放置, 需要多宽.
    QFontMetrics metrics(this->label->font());
    int totalWidth = metrics.horizontalAdvance(this->label->text());

    // 3. 计算出此处的行数是多少 (40 表示左右各有 20px 的边距)
    int rows = (totalWidth / (width - 40)) + 1;
    if(rows == 1)
    {
        // 如果此时得到的行数就只有一行
        width = totalWidth + 40;
    }

    // 4. 根据行数, 计算得到高度. (20 表示上下各有 10px 的边距)
    int height = rows * (this->label->font().pixelSize() * 1.2) + 20;

    // 5. 绘制圆角矩形和箭头
    QPainter painter(this);
    QPainterPath path;
    // 设置 "抗锯齿"
    painter.setRenderHint(QPainter::Antialiasing);
    if(_isLeft)
    {
        // 设置画笔颜色
        painter.setPen(QPen(QColor(255,255,255)));
        // 填充颜色
        painter.setBrush(QColor(255,255,255));

        // 绘画图形都是先圈起来再进行填充
        // 绘制圆角矩形
        painter.drawRoundedRect(10,0,width,height,10,10);
        // 绘画箭头
        path.moveTo(10,15); // 起点
        path.lineTo(0,20);
        path.lineTo(10,25); //终点
        // 绘制的线形成闭合的多边形, 才能进行使用 Brush 填充颜色.
        // 起点和终点连线
        path.closeSubpath();
        painter.drawPath(path);     // 不要忘记真正的绘制操作

        this->label->setGeometry(10,0,width,height);
    }
    else
    {
        // 设置画笔颜色
        painter.setPen(QPen(QColor(137, 217, 97)));
        // 填充颜色
        painter.setBrush(QColor(137, 217, 97));

        // 圆角矩形左侧边的横坐标位置
        // 10 是用来容纳 箭头 的宽度
        int leftPos = this->width() - width - 10;
        // 圆角矩形右侧边的横坐标位置
        int rightPos = this->width() - 10;
        // 绘制圆角矩形
        painter.drawRoundedRect(leftPos,0,width,height,10,10);
        // 绘制箭头
        path.moveTo(rightPos,15);
        path.lineTo(this->width(),20);
        path.lineTo(rightPos,25);
        // 绘制的线形成闭合的多边形, 才能进行使用 Brush 填充颜色.
        // 起点和终点连线
        path.closeSubpath();
        painter.drawPath(path);     // 不要忘记真正的绘制操作

        this->label->setGeometry(leftPos,0,width,height);
    }

    // 6. 重新设置父元素的高度, 确保父元素足够高, 能够容纳下上述绘制的消息显示的区域
    // 注意高度要涵盖之前名字和时间的 label 的高度, 以及留点冗余空间.
    parent->setFixedHeight(height + 50);
}














